#include "Console.hpp"
void Console::Register(ConsoleAccessable *consolable)
{
    if (consolable != NULL)
        items.push_back(consolable);
}
void Console::Log(std::string lines)
{
    //std::string toAdd = output.getText() + "----  Log  ---- \n " + lines + " \n ----End Log---- \n\n ";
    //output.setText(toAdd);
    //output.scrollToBottom();
}

bool Console::Visible()
{
    return consoleVisible;
}

bool Console::Visible(bool tf)
{
    bool res = consoleVisible;
    consoleVisible = tf;
    RecalcSizes();
    return res;
}


bool Console::KeysDown(sf::Event::KeyEvent key)
{

    RecalcSizes();

    return true;
}

bool Console::KeysUp(sf::Event::KeyEvent key)
{
    if (!consoleVisible)
        return false;
    return true;
}

void Console::Draw ()
{
    if (consoleVisible)
    {
        //output.Draw();
        //input.Draw();
    }
}

void Console::Update(double dTime)
{

}

void Console::Resize()
{
    RecalcSizes();
    //Log("Window Resized to: " + fToS(Window::GetDimentions().x) + "x" + fToS(Window::GetDimentions().y));
}


/*static*/ Console* Console::Instance()
{
    if (instance == NULL)
        instance = new Console();
    return instance;
}

// Private functions / vars

Console::Console()/* :
    input("CONSOLE_INPUT", "", false), output("CONSOLE_OUTPUT", "", false)*/
{
    instance = this;

    /*
    output.setAcceptableInput(INPUT_TYPE_ALL);
    output.setEditable(false);
    output.SetOneLine(false);
    output.setFaceColor(Vec3d(0.0, 0.0, 0.0));

    input.setAcceptableInput(INPUT_TYPE_ALL);
    input.setEditable(false);
    input.SetOneLine(false);    // uhh, we don't care really...
    input.setFaceColor(Vec3d(0.1, 0.0, 0.0));

    consoleVisible = false;
    RecalcSizes();

    std::ifstream input("resources\\keybindings.file");
    std::string line;

    int key = -1;
    std::string tmp;

    input >> tmp;
    while (!input.eof())
    {
        if (tmp.compare("#") == 0)
      {
          // we're starting a new command
        input >> key;
          input >> tmp;
        while (!input.eof())
        {
        if (tmp.compare("#") == 0)
          break;		//exit inner loop
          // otherwise we push back the string token
        keybinds[key].push_back(tmp);
            input >> tmp;
        }
      }
      else
      {
        Log("Error: invalid format of keybinds file!");
        break;	// exit outer loop
      }
    }
    input.close();
    */
}

/*static*/ Console* Console::instance = NULL;

std::string Console::ExecuteCommand(std::deque<std::string> tokens)
{
    std::string command = tokens[0];    // isolate the first token as a 'command'
    tokens.pop_front();                 // remove the first token from the rest

    std::string result = "Unrecognized command: \"" + command + "\"";
    if (command.compare("exit") == 0)
    {
        App::I().Exit();
        result = "Exiting program...";
    }
    else if (command.compare("help") == 0)
    {
        result = "List of commands: \n ";
        for (unsigned int i = 0; i < items.size(); i++)
        {
            result = result + "  " + items[i]->CommandName() + " \n ";
        }
        // system commands?
        result = result + " bind\n";
        result = result + " \n Type a command name without any other parameters to see more about that command";
    }
    else if (command.compare("bind") == 0)
    {
        result = BindCommand(tokens);
    }
    for (unsigned int i = 0; i < items.size(); i++)
    {
        if (command.compare(items[i]->CommandName()) == 0)
        {
            result = items[i]->ExecuteCommand(tokens);
        }
    }
    return result;
}

void Console::ExecuteCurrentCommand()
{
//      std::deque<std::string> stringTokens = Tokenize(input.getText());

//      std::string result = ExecuteCommand(stringTokens);
//      // now put the result text in the console
//      output.setText(output.getText() + ">" + input.getText() + " \n " + result + " \n\n ");
//      output.scrollToBottom();    // move us all the way down
//      // and clear the input
//      input.setText("");
}

void Console::RecalcSizes()
{
  int height = App::I().GetWindow().getSize().y;
  int width = App::I().GetWindow().getSize().x;
  //output.setPosition(Vec2i(0,height - 300));
  //output.setSize(Vec2i(width, 300));

  //input.setPosition(Vec2i(0, height - 325));
  //input.setSize(Vec2i(width, 25));
}

std::deque<std::string> Console::Tokenize (std::string input)
{
  std::deque<std::string> result;
  int spacePosition = 0;
  std::string token = "";

  while (input.length() > 0)
  {
      spacePosition = input.find_first_of(" ,");
      token = input.substr(0, spacePosition);
      if (token.length() != 0 && token.find_first_of(" ,") == token.npos)   // eliminate zero size tokens and ones that contain spaces
          result.push_back(token);
      if (spacePosition == input.npos )
      {
          input = "";
      }
      else
      {
          input = input.substr(spacePosition + 1);
      }
  }
  if (result.size() == 0)
    result.push_back("");  // push back at least one result
  return result;
}

std::string Console::BindCommand(std::deque<std::string> tokens)
{
    if (tokens.size() == 0)
        return "Bind commands: \n bind [f1..12] [command]\n bind list";

    std::string cmd = tokens[0];
    tokens.pop_front();

    if (cmd.compare("list") == 0)
    {
        std::string result = "No keybinds set";
        if (keybinds.size() > 0)
        {
            result = "Current keybinds:";
            std::map<int, std::deque<std::string> >::iterator key;
            for (key = keybinds.begin(); key != keybinds.end(); ++key)
            {
                result.append("\n- f" + fToS(key->first - 304) + " > ");
                for (unsigned int i=0; i<key->second.size(); i++)
                {
                    result.append(key->second[i]);
                    result.append(" ");
                }
            }
            result.append("\n");
        }
        return result;
    }
    else
    {
//        int keyCode;
        // TODO: Fix this to not use sscanf_s
//          if (sscanf_s(cmd.c_str(), "f%d", &keyCode))
//          {
//              keyCode += 304;
//              if (keyCode >= sf::Keyboard::F1 && keyCode <= sf::Keyboard::F12)
//              {
//                  keybinds[keyCode] = tokens;
//                  std::string command;
//                  for (unsigned int i=0; i<tokens.size(); i++)
//                  {
//                      command.append(" ");
//                      command.append(tokens[i]);
//                  }
//                  // save keybinds to file
//                  StoreKeybinds();
//                  return "Bind: " + cmd + " > " + command;
//              }
//              else
//              {
//                  return "Bind error: Only allowed to bind key F1 to F12";
//              }
//          }
    }

    return "Bind commands: \n bind [f1..12] [command]\n bind list";
}

void Console::StoreKeybinds()
{
    std::map<int, std::deque<std::string> >::iterator key;
    std::ofstream output;
    output.open("resources\\keybindings.file");
    for (key = keybinds.begin(); key != keybinds.end(); ++key)
    {
        output << "#\n";
        output << key->first << "\n";
        for (unsigned int i = 0; i < key->second.size(); i++)
            output << key->second[i] << "\n";
    }
    output.close();
}
